/////////////////// comment /////////////////////

#include <vector>
#include "combined.h"
#include "command.h"
#include "commandTable.h"
#include "definitions.h"
#include "log.h"
#include "stringutil.h"
#include "timestamp.h"
#include "world.h"

// Command definitions for commands beginning with the letters Q through S
// (Keep in alphabetical order... it's MUCH easier)
CmdQuit::CmdQuit( void ) {
	setName( "quit" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( true );
	setTags( "quit" );
	addSyntax( "syntax: quit    {CDisconnect from the server" );
	addHelp( "When you quit, your data is automatically saved, and then" );
	addHelp( "your connection is terminated." );
}

bool CmdQuit::execute( Character* character, const std::string& args ) {

	character->record( "Logged out." );
	character->setDisconnected( true );

	return true;
}

CmdReboot::CmdReboot( void ) {
	setName( "reboot" );
	setLevel( HEAD );
	setEnabled( true );
	setOmniset( true );
	setTags( "reboot copyover shutdown" );
	addSyntax( "syntax: reboot    {CPerform a hot-reboot of the server." );
	addHelp( "Reboot will save all world, server, and current player data" );
	addHelp( "before killing the current server, starting a new instance," );
	addHelp( "reloading all data, and then re-establishing the saved connections." );
	addHelp( "A reboot is also commonly referred to as a \"copyover\"" );
}

bool CmdReboot::execute( Character* character, const std::string& args ) {
	World::Instance().copyover();
	return true;
}

CmdRedit::CmdRedit( void ) {
	setName( "redit" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "aedit medit nedit oedit pedit redit" );
	addSyntax( "syntax: redit              {Center the room editor" );
	addSyntax( "        redit make <vnum>  {Ccreate a new room and begin editing it" );
}

bool CmdRedit::execute( Character* character, const std::string& args ) {
	std::string input, s_vnum;
	Room* room = NULL;
	Area* area = NULL;
	unsigned vnum = 0;

	split( args, input, s_vnum );
	input = trim( input );

	if ( input == "make" ) {
		vnum = atoi( s_vnum.c_str() );
		// Check permissions...
		if ( ( area = World::Instance().getParentArea( vnum ) ) == NULL ) {
			character->Send( "Invalid vnum." );
			return false;
		}
		if ( !area->hasPermission( character ) ) {
			character->Send( "You don't have permission to that area." );
			return false;
		}
		// Make sure the Room doesn't already exist...
		if ( World::Instance().getRoom( vnum ) ) {
			character->Send( "That room already exists." );
			return false;
		}
		// Create the Room...
		rCmdMake make;
		make.execute( character, to_str( vnum ) );
		if ( ( room = World::Instance().getRoom( vnum ) ) == NULL ) {
			character->Send( "An error has occured." );
			return false;
		}
		// Send them to the Room...
		CmdGoto go;
		go.execute( character, to_str( room->getVnum() ) );
		// Give them a message...
		character->Send( "Welcome to Symphony Edit Mode (SEM) for Rooms!" );
		character->setStatus( REDIT );
		return true;
	} else {
		if ( character->getRoom()->getVnum() < START_VNUM ) {
			character->Send( "You can't edit this room." );
			return false;
		}
		character->setStatus( REDIT );
		character->Send( "Welcome to Symphony Edit Mode (SEM) for Rooms!" );
		return true;
	}

	return true;
}

CmdReply::CmdReply( void ) {
	setName( "reply" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "reply tell channels" );
	addSyntax( "syntax: reply <message>    {Crespond to a \"tell\" with the given message" );
	addHelp( "Reply is an OOC (Out Of Character) channel." );
	addHelp( "Reply sends the given message to the last player who used the \"tell\" command" );
	addHelp( "to communicate with you, if that player can be found." );
}

bool CmdReply::execute( Character* character, const std::string& args ) {
	std::string name;
	std::string message;
	Character* target;

	if ( ( target = World::Instance().getCharacter( character->getReply() ) ) == NULL ) {
		character->Send( "That target cannot be found." );
		return false;
	}

	target->Send( character->getName() + " tells you '{Y" + args + "{x'" );
	target->setReply( character->getName() );
	character->Send( "You tell " + target->getName() + " '{Y" + args + "{x'" );

	return true;
}

CmdSave::CmdSave( void ) {
	setName( "save" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "save quit" );
	addSyntax( "syntax: save     {CSave your player data" );
}

bool CmdSave::execute( Character* character, const std::string& args ) {
	character->save();
	character->Send( "Your data has been saved." );
	return true;
}

CmdSay::CmdSay( void ) {
	setName( "say" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "say channels" );
	addSyntax( "syntax: say <message>    {Cdisplays the given message to the room" );
	addHelp( "\"say\" is an IC (In Character) channel." );
}

bool CmdSay::execute( Character* character, const std::string& args ) {
	std::string args1;
	std::string buf1;
	std::string buf2;

	if ( args.empty() )
		return true;

	if ( args.length() > MAX_BUFFER ) {
		args1.append( args, 0, MAX_BUFFER );
	} else {
		args1 = args;
	}
	args1 = trim( args1 );

	character->getRoom()->send( character->getName() + " says '{G" + args1 + "{x'" );
	character->Send( "You say, '{G" + args1 + "{x'" );

	return true;
}

CmdScore::CmdScore( void ) {
	setName( "score" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "score data information statistics stats" );
	addSyntax( "syntax: score     {Cdisplay your current profile data" );
}

bool CmdScore::execute( Character* character, const std::string& args ) {
	std::string temp; // for format()
	std::string score;
	std::string name;
	name << character->getName() << ' ' << character->getLastName();
	
	score << " ___________________________________________________________________________\n\r";
	score << "|\\_________________________________________________________________________/|\n\r";
	score << "||Name:  " << format( 25, name, temp, 'c' );
	score << " ||level: " << format( 3, character->getLevel(), temp, 'Y' );
	score << "       ||gender: " << format( 7, Creature::gender2string( character->getGender() ), temp, 'B' ) << "    ||\n\r";
	score << "||Race:  " << format( 12, Creature::race2string( character->getRace() ), temp, 'c' );
	score << "              ||hp:    " << format( 4, character->getHp(), temp, 'G' );
	score << "/" << format( 4, character->getMaxHp(), temp, 'g' );
	score << " ||hand:   " << format( 5, Character::hand2string( character->getHand() ), temp, 'B' ) << "      ||\n\r";
	score << "||Class: " << format( 12, Creature::class2string( character->getClass() ), temp, 'c' );
	score << "              ||mana:  " << format( 4, character->getMana(), temp, 'C' );
	score << "/" << format( 4, character->getMaxMana(), temp, 'c' ) << " ||height: ";
	score << format( 10, character->getHeight(), temp, 'B' ) << " ||\n\r";
	score << "||Clan:  " << format( 12, character->getClan(), temp, 'c' );
	score << "              ||move:  " << format( 4, character->getMove(), temp, 'B' );
	score << "/" << format( 4, character->getMaxMove(), temp, 'b' );
	score << " ||weight: " << format( 10, character->getWeight(), temp, 'B' ) << " ||\n\r";
	score << "||_________________________________||_________________||___________________||\n\r";
	score << "||_________________________________________________________________________||\n\r";
	score << "||hr/dr: " << format( 3, character->getHr(), temp, 'R' );
	score << "/" << format( 3, character->getDr(), temp, 'R' );
	score << "                  ||str: " << format( 2, character->getStr(), temp, 'G' );
	score << "/" << format( 2, character->getMaxStr(), temp, 'g' );
	score << "     ||age:    " << format( 4, character->getAge(), temp, 'M' ) << "          ||\n\r";
	score << "||saves: " << format( 5, character->getSaves(), temp, 'R' );
	score << "                    ||dex: " << format( 2, character->getDex(), temp, 'G' );
	score << "/" << format( 2, character->getMaxDex(), temp, 'g' );
	score << "     ||tnl:    " << format( 7, character->getTnl(), temp, 'M' ) << "       ||\n\r";
	score << "||                                ||con: " << format( 2, character->getCon(), temp, 'G' );
	score << "/" << format( 2, character->getMaxCon(), temp, 'g' );
	score << "     ||exp:    " << format( 6, character->getExp(), temp, 'M' ) << "        ||\n\r";
	score << "||        ac: " << format( 4, character->getAc(), temp, 'R' );
	score << "                ||int: " << format( 2, character->getIntel(), temp, 'G' );
	score << "/" << format( 2, character->getMaxIntel(), temp, 'g' );
	score << "     ||pracs:  " << format( 4, character->getPractices(), temp, 'M' );
	score << "          ||\n\r";
	score << "||  bash:   " << format( 4, character->getAcBash(), temp, 'R' );
	score << " slash:  " << format( 4, character->getAcSlash(), temp, 'R' );
	score << "     ||wis: " << format( 2, character->getWis(), temp, 'G' );
	score << "/" << format( 2, character->getMaxWis(), temp, 'g' );
	score << "     ||trains: " << format( 4, character->getTrains(), temp, 'M' ) << "          ||\n\r";
	score << "||  pierce: " << format( 4, character->getAcPierce(), temp, 'R' );
	score << " exotic: " << format( 4, character->getAcExotic(), temp, 'R' );
	score << "     ||cha: " << format( 2, character->getCha(), temp, 'G' );
	score << "/" << format( 2, character->getMaxCha(), temp, 'g' );
	score << "     ||gains:  " << format( 4, character->getGains(), temp, 'M' ) << "          ||\n\r";
	score << "||________________________________||_______________||______________________||\n\r";
	score << "||_________________________________________________________________________||\n\r";
	score << "||gold: " << format( 8, character->getGold(), temp, 'Y' );
	score << "        ||items: " << format( 4, character->getInventory().size(), temp, 'm' );
	score << "  weight: " << format( 6, character->getWeight(), temp, 'm' ) << "                      ||\n\r";
	score << "||silver: " << format( 8, character->getSilver(), temp, 'W' );
	score << "      ||points: " << format( 6, character->getPoints(), temp, 'm' ) << "                                   ||\n\r";
	score << "||bank: " << format( 7, character->getBankGold(), temp, 'Y' );
	score << "/" << format( 7, character->getBankSilver(), temp, 'W' );
	score << " ||house: " << format( 41, character->getHouse(), temp, 'm' ) << " ||\n\r";
	score << "||______________________||_________________________________________________||\n\r";
	score << "|/_________________________________________________________________________\\|";

	character->Send( score );
	return true;
}

CmdShutdown::CmdShutdown( void ) {
	setName( "shutdown" );
	setLevel( HEAD );
	setEnabled( true );
	setOmniset( true );
	setTags( "shutdown reboot copyover" );
	addSyntax( "syntax: shutdown     {Cshuts down the server" );
	addHelp( "Shutdown will save all world, server, and current player data" );
	addHelp( "before exiting the server process." );
}

bool CmdShutdown::execute( Character* character, const std::string& args ) {
	World::Instance().omninet( "Symphony is being shut down." );
	World::Instance().die();
	return true;
}

/*CmdSiteban::CmdSiteban( void ) {
	setName( "siteban" );
	setLevel( HEAD );
	setEnabled( true );
	setOmniset( true );
}

bool CmdSiteban::execute( Character* character, const string& args ) {

	return false;
}*/

CmdSockets::CmdSockets( void ) {
	setName("sockets");
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	setTags( "sockets connections" );
	addSyntax( "syntax: sockets       {Clist all player connections, and their socket/ip data" );
}

bool CmdSockets::execute( Character* character, const std::string& args ) {
	std::string buf;
	unsigned count = 0;

	for ( std::map<std::string,Character*>::iterator it = World::Instance().getCharacters().begin(); it != World::Instance().getCharacters().end(); ++it, ++count )
		buf << "\n\r" << (*it).second->getName() << " @ {C" << (*it).second->getSocket()->GetSocketHost() << "{x => {c" << (*it).second->getSocket()->GetSocketIP() << "{x (descriptor: {W" << (*it).second->getSocket()->GetDescriptor() << "{x)";

	if ( count == 1 )
         buf.insert( 0, "\t\t1 Socket" );
	else
	     buf.insert( 0, "\t\t" + to_str( count ) + " Sockets\n\t" );
	character->Send( buf );
	return true;
}

CmdSouth::CmdSouth( void ) {
	setName( "south" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "north east south west up down movement" );
	addSyntax( "syntax: south     {Cmove south" );
}

bool CmdSouth::execute( Character* character, const std::string& args ) {
	std::string buf;
	Exit* in = character->getRoom()->getExit( SOUTH );
	
	if ( !in->getThere() ) {
		buf << "There is no exit that way.";
		character->Send( buf );
		return true;
	}
	else if ( in->getDoor() && !in->getOpen() ) {
		buf << "That door is closed.";
		character->Send( buf );
		return true;
	}
	else {
		Room* from = character->getRoom();
		Room* to = NULL;
		if ( ( to = World::Instance().getRoom( in->getPoint() ) ) == NULL ) {
			character->Send( "You can't go there." );
			std::string message = "Exit inconsistency: ";
			message << from->getVnum() << " south to " << in->getPoint();
			log( message, WORLD );
			return false;
		}

		from->drop( character );
		from->send( character->getName() + " has left to the south." );
		to->send( character->getName() + " has arrived from the north." );
		to->add( character );
		character->setRoom( to );

		// Force the "look" Command...
		std::string empty;
		CmdLook commandLook;
		commandLook.execute( character, empty );
	}

	return true;
}

CmdSummon::CmdSummon( void ) {
	setName( "summon" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "transport goto" );
	addSyntax( "sytnax: summon <player|mob>  {Ctransports the target into the room" );
}

bool CmdSummon::execute( Character* character, const std::string& args ) {
	std::string name = trim( args );
	Character* c_target = NULL;
	Mob* m_target = NULL;
	Room* to = character->getRoom();
	Room* from = NULL;

	if ( ( c_target = World::Instance().getCharacter( name ) ) ) {
		from = c_target->getRoom();
		from->drop( c_target );
		from->send( c_target->getName() + " disappears in a puff of smoke." );
		to->send( c_target->getName() + " appears in a puff of smoke." );
		to->add( c_target );
		c_target->setRoom( to );
		CmdLook look;
		look.execute( c_target, " " );
		c_target->Send( "\n\r\n\rYou've been summoned." );
		return true;
	}

	if ( ( m_target = World::Instance().getMob( name ) ) ) {
		from = m_target->getRoom();
		from->drop( m_target );
		from->send( m_target->getShortDesc() + " disappears in a puff of smoke." );
		to->send( m_target->getShortDesc() + " appears in a puff of smoke." );
		to->add( m_target );
		m_target->setRoom( to );
		return true;
	}

	character->Send( "That target can't be found." );
	return false;
}
